using System;
using System.Collections.Specialized;
using System.Configuration.Provider;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Security;

namespace MembershipAdapter
{
    public class MembershipProviderSettings
    {
        #region Fields

        private NameValueCollection config;

        #endregion Fields

        #region Properties

        public string AppName { get; set; }

        public int CommandTimeout { get; set; }

        public bool EnablePasswordReset { get; set; }

        public bool EnablePasswordRetrieval { get; set; }

        public int MaxInvalidPasswordAttempts { get; set; }

        public int MinRequiredNonalphanumericCharacters { get; set; }

        public int MinRequiredPasswordLength { get; set; }

        public int PasswordAttemptWindow { get; set; }

        public MembershipPasswordFormat PasswordFormat { get; set; }

        public string PasswordStrengthRegularExpression { get; set; }

        public bool RequiresQuestionAndAnswer { get; set; }

        public bool RequiresUniqueEmail { get; set; }

        #endregion Properties

        #region Ctors

        public MembershipProviderSettings(NameValueCollection config)
        {
            this.config = config;
        }

        #endregion Ctors

        #region Methods

        public virtual NameValueCollection Initialize(bool throwOnError = true)
        {
            this.EnablePasswordRetrieval = SecUtility.GetBooleanValue(this.config, "enablePasswordRetrieval", false);
            this.EnablePasswordReset = SecUtility.GetBooleanValue(this.config, "enablePasswordReset", true);
            this.RequiresQuestionAndAnswer = SecUtility.GetBooleanValue(this.config, "requiresQuestionAndAnswer", true);
            this.RequiresQuestionAndAnswer = SecUtility.GetBooleanValue(this.config, "requiresUniqueEmail", true);
            this.MaxInvalidPasswordAttempts = SecUtility.GetIntValue(this.config, "maxInvalidPasswordAttempts", 5, false,
                                                                     0);
            this.PasswordAttemptWindow = SecUtility.GetIntValue(this.config, "passwordAttemptWindow", 10, false, 0);
            this.MinRequiredPasswordLength = SecUtility.GetIntValue(this.config, "minRequiredPasswordLength", 7, false,
                                                                    128);
            this.MinRequiredNonalphanumericCharacters = SecUtility.GetIntValue(this.config,
                                                                               "minRequiredNonalphanumericCharacters", 1,
                                                                               true, 128);
            this.PasswordStrengthRegularExpression = this.config["passwordStrengthRegularExpression"];

            if (this.PasswordStrengthRegularExpression != null)
            {
                this.PasswordStrengthRegularExpression = this.PasswordStrengthRegularExpression.Trim();
                if (this.PasswordStrengthRegularExpression.Length != 0)
                {
                    try
                    {
                        new Regex(this.PasswordStrengthRegularExpression);
                    }
                    catch (ArgumentException e)
                    {
                        throw new ProviderException(e.Message, e);
                    }
                }
            }
            else
            {
                this.PasswordStrengthRegularExpression = string.Empty;
            }

            if (this.MinRequiredNonalphanumericCharacters > this.MinRequiredPasswordLength)
            {
                throw new HttpException(
                    SR.GetString(SR.MinRequiredNonalphanumericCharacters_can_not_be_more_than_MinRequiredPasswordLength));
            }

            this.CommandTimeout = SecUtility.GetIntValue(this.config, "commandTimeout", 30, true, 0);
            this.AppName = this.config["applicationName"];
            if (string.IsNullOrEmpty(this.AppName))
            {
                this.AppName = SecUtility.GetDefaultAppName();
            }

            if (this.AppName.Length > 256)
            {
                throw new ProviderException(SR.GetString(SR.Provider_application_name_too_long));
            }

            var strTemp = this.config["passwordFormat"] ?? "Hashed";
            switch (strTemp)
            {
                case "Clear":
                    this.PasswordFormat = MembershipPasswordFormat.Clear;
                    break;

                case "Encrypted":
                    this.PasswordFormat = MembershipPasswordFormat.Encrypted;
                    break;

                case "Hashed":
                    this.PasswordFormat = MembershipPasswordFormat.Hashed;
                    break;

                default:
                    throw new ProviderException(SR.GetString(SR.Provider_bad_password_format));
            }

            if (this.PasswordFormat == MembershipPasswordFormat.Hashed && this.EnablePasswordRetrieval)
            {
                throw new ProviderException(SR.GetString(SR.Provider_can_not_retrieve_hashed_password));
            }

            // NB: use Encryption package instead.
            //if (this.PasswordFormat == MembershipPasswordFormat.Encrypted && MachineKeySection.IsDecryptionKeyAutogenerated)
            //{
            //    throw new ProviderException(SR.GetString(SR.Can_not_use_encrypted_passwords_with_autogen_keys));
            //}

            if (throwOnError)
            {
                this.config.Remove("enablePasswordRetrieval");
                this.config.Remove("enablePasswordReset");
                this.config.Remove("requiresQuestionAndAnswer");
                this.config.Remove("applicationName");
                this.config.Remove("requiresUniqueEmail");
                this.config.Remove("maxInvalidPasswordAttempts");
                this.config.Remove("passwordAttemptWindow");
                this.config.Remove("commandTimeout");
                this.config.Remove("passwordFormat");
                this.config.Remove("name");
                this.config.Remove("minRequiredPasswordLength");
                this.config.Remove("minRequiredNonalphanumericCharacters");
                this.config.Remove("passwordStrengthRegularExpression");
                if (this.config.Count > 0)
                {
                    var attribUnrecognized = this.config.GetKey(0);
                    if (string.IsNullOrEmpty(attribUnrecognized) == false)
                    {
                        throw new ProviderException(SR.GetString(SR.Provider_unrecognized_attribute, attribUnrecognized));
                    }
                }
            }

            return this.config;
        }

        #endregion Methods
    };
}